﻿# coding: utf-8
import wx
import os
import fnmatch

import Entity
import ResourceManager

from wxFramework.Dialog import wxDialogTerrainCreate
from wxFramework.Dialog import wxDialogWaterCreate

class wxPanelAssets(wx.Panel):
    
    def __OnReloadRes(self, e):
        ResourceManager.ReloadAllResource()
        
    def __init__(self, parent, id):
        """ Default class constructor """

        wx.Panel.__init__(self, parent, id)

        # create tree control.
        self._treeAssets = wx.TreeCtrl(self, -1, size = (300, -1))

        self._reloadRes = wx.Button(self, -1, u'Reload')
        self.Bind(wx.EVT_BUTTON, self.__OnReloadRes, self._reloadRes)
        
        # layout
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self._reloadRes, 0)
        sizer.Add(self._treeAssets, 1, wx.ALL|wx.EXPAND, border = 5)
        self.SetSizer(sizer)

        # make image list
        il = wx.ImageList(IL.IMAGE_SMALL, IL.IMAGE_SMALL)
        self._bmpIdxFolderNormal = il.Add(IL.GetBitmap(IL.ID_IMAGE_FILE_FOLDER_CLOSE, IL.IMAGE_SMALL))
        self._bmpIdxFolderExpand = il.Add(IL.GetBitmap(IL.ID_IMAGE_FILE_FOLDER_OPEN, IL.IMAGE_SMALL))
        self._bmpIdxFile = il.Add(IL.GetBitmap(IL.ID_IMAGE_FILE_NORMAL, IL.IMAGE_SMALL))
        self._bmpIdxFileSel = il.Add(IL.GetBitmap(IL.ID_IMAGE_FILE_SELECTED, IL.IMAGE_SMALL))
        self._bmpIdxType = il.Add(IL.GetBitmap(IL.ID_IMAGE_ASSETS_TYPE, IL.IMAGE_SMALL))
        self._bmpIdxRoot = il.Add(IL.GetBitmap(IL.ID_IMAGE_ASSETS, IL.IMAGE_SMALL))
        self._treeAssets.SetImageList(il)
        self._il = il

        # add item to assets tree
        self._root = self._treeAssets.AddRoot(TD.ASSETS_LIST, self._bmpIdxRoot)

        self._itemTerrainType = self._treeAssets.AppendItem(self._root, TD.ASSETS_TYPE_TERRAIN, self._bmpIdxType)
        self._itemModelType = self._treeAssets.AppendItem(self._root, TD.ASSETS_TYPE_MODEL, self._bmpIdxType)
        self._itemEffectType = self._treeAssets.AppendItem(self._root, TD.ASSETS_TYPE_EFFECT, self._bmpIdxType)
        self._itemWaterType = self._treeAssets.AppendItem(self._root, TD.ASSETS_TYPE_WATER, self._bmpIdxType)
        self._itemPostProcessType = self._treeAssets.AppendItem(self._root, TD.ASSETS_TYPE_POST_PROCESS, self._bmpIdxType)
        self._itemSceneLightType = self._treeAssets.AppendItem(self._root, TD.ASSETS_TYPE_SCENE_LIGHT, self._bmpIdxType)

        self._treeAssets.ExpandAll()

        # bind all event
        self._treeAssets.Bind(wx.EVT_KEY_DOWN, self.__OnTreeKeyDown)
        self._treeAssets.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.__OnTreeItemActive)
        self._treeAssets.Bind(wx.EVT_TREE_SEL_CHANGED, self.__OnTreeItemSelChanged)
        self.Bind(wx.EVT_CONTEXT_MENU, self.__OnContextMenu)

        self._idMenuRefreshResList = wx.NewId()
        self.Bind(wx.EVT_MENU, self.__OnMenuRefreshResList, id = self._idMenuRefreshResList)

    def __OnContextMenu(self, e):
        menu = wx.Menu()
        menu.Append(self._idMenuRefreshResList, TD.REFRESH_ASSETS_LIST)
        self.PopupMenu(menu)
        menu.Destroy()

    def __OnMenuRefreshResList(self, e):
        self.OnUpdateTreeList()

    def __OnTreeKeyDown(self, e):
        code = e.GetKeyCode()
        if code == wx.WXK_F5:
            self.OnUpdateTreeList()

    def __OnCreateTerrain(self):
        dlg = wxDialogTerrainCreate(self)
        if dlg.ShowModal() == wx.ID_OK:
            try:
                width = dlg.GetWidth()
                height = dlg.GetHeight()
                shaderFile = dlg.GetShaderFile()
                defaultLayerFile = dlg.GetDefaultLayerFile()
            except:
                dlgMsg = wx.MessageDialog(self, TD.ERR_PARAM_INVALID, TD.ERROR, wx.OK|wx.ICON_INFORMATION)
                dlgMsg.ShowModal()
                dlgMsg.Destroy()
                dlg.Destroy()
                return
                
            if not TERRAIN_EDITOR.CreateTerrain(width, height, shaderFile, defaultLayerFile):
                dlgMsg = wx.MessageDialog(self, TD.ERR_CREATE_TERRAIN_FAILED, TD.ERROR, wx.OK|wx.ICON_INFORMATION)
                dlgMsg.ShowModal()
                dlgMsg.Destroy()
                
        dlg.Destroy()
        
    def __OnCreateWater(self):
        if WORLD_EDITOR.GetCurrentOperate() != OPD.OP_BUILD_SINGLE:
            return
        
        dlg = wxDialogWaterCreate(self)
        if dlg.ShowModal() == wx.ID_OK:
            try:
                width = dlg.GetWidth()
                length = dlg.GetLength()
                gridSize = dlg.GetGridSize()
                shaderFile = dlg.GetShaderFile()
                bumpTextureFile = dlg.GetBumpTextureFile()
            except:
                dlgMsg = wx.MessageDialog(self, TD.ERR_PARAM_INVALID, TD.ERROR, wx.OK|wx.ICON_INFORMATION)
                dlgMsg.ShowModal()
                dlgMsg.Destroy()
                dlg.Destroy()       
                return
            
            BUILDER_SINGLE.SetWaterObject(gridSize, width, length, shaderFile, bumpTextureFile)

    def __OnTreeItemSelChanged(self, e):
        item = e.GetItem()
        if item == self._itemPostProcessType:
            PANEL_PROPERTY.SetPanelProperty(PANEL_PROP_POST_PROCESS)
        elif item == self._itemSceneLightType:
            PANEL_PROPERTY.SetPanelProperty(PANEL_PROP_SCENE_LIGHT)
            PANEL_PROP_SCENE_LIGHT.UpdateUI()
        
        e.Skip()
        
    def __OnTreeItemActive(self, e):
        # Get data associate with the tree item
        item = e.GetItem()
        
        # Create terrain.
        if item == self._itemTerrainType:
            self.__OnCreateTerrain()
            return
        elif item == self._itemWaterType:
            self.__OnCreateWater()
            return
            
        data = self._treeAssets.GetItemPyData(item)
        if not data:
            e.Skip()
            return

        # Get the file path name
        fullPath, itemType = data
        filePath = REMOVE_ROOT_PATH(fullPath)
        
        # Set object when current is in build state.
        op = WORLD_EDITOR.GetCurrentOperate()
        if op == OPD.OP_BUILD_SINGLE:
            if itemType == self._itemModelType:
                BUILDER_SINGLE.SetModelObject(filePath)
            
        e.Skip()
        
    def OnUpdateTreeList(self):
        # refresh model list
        self._treeAssets.DeleteChildren(self._itemModelType)
        root = GLOBAL_SETTING._workDir + GLOBAL_SETTING._modelDir
        self.WalkDirectoryTree(self._itemModelType, root, ['*.model.xml'], self._itemModelType)

        # refresh effect list
        self._treeAssets.DeleteChildren(self._itemEffectType)
        root = os.path.join(GLOBAL_SETTING._workDir, GLOBAL_SETTING._effectDir)
        self.WalkDirectoryTree(self._itemEffectType, root, ['*.xml'], self._itemEffectType)

    def WalkDirectoryTree(self, node, root, ext, itemType):
        listDir = os.listdir(root)
        for d in listDir:
            fullPath = os.path.join(root, d)
            if os.path.isdir(fullPath):
                subNode = self._treeAssets.AppendItem(node, d, self._bmpIdxFolderNormal, self._bmpIdxFolderExpand)
                self.WalkDirectoryTree(subNode, fullPath, ext, itemType)
            elif os.path.isfile(fullPath):
                for pat in ext:
                    if fnmatch.fnmatch(d, pat):
                        fnode = self._treeAssets.AppendItem(node, d, self._bmpIdxFile, self._bmpIdxFileSel)
                        self._treeAssets.SetPyData(fnode, (fullPath, itemType))
                        break